package net.media.datafw.transport.model;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;

import net.media.datafw.model.Field;
import net.media.datafw.transport.TransportException;
import net.media.datafw.transport.Transporter;

public class TransportField extends Field {
	private String fieldArrayName = null;
	private boolean dotransport = true;
	private boolean isAttribute = false;
	private boolean isArray = false;
	private boolean isPrimitive = false;
	private Type rawType = null;
	private Type componentValueType = null;

	public TransportField(Method getMethod, Method setMethod) {
		super(getMethod, setMethod);
		this.fieldArrayName = this.fieldName + "s";
		this.type = getMethod.getGenericReturnType();
		isAttribute = type instanceof Class<?> && !((Class<?>) type).isArray();
		if (isAttribute && type instanceof Class<?> && Transporter.isTransportable((Class<?>) type)) {
			isAttribute = false;
		}

		if (this.type instanceof Class<?>) {
			rawType = this.type;
			this.componentValueType = ((Class<?>) type).getComponentType();
			this.isArray = ((Class<?>) type).isArray();
			if (isArray) {
				isPrimitive = ((Class<?>) type).getComponentType().isPrimitive();
			} else {
				isPrimitive = ((Class<?>) type).isPrimitive();
			}
		} else if (this.type instanceof GenericArrayType) {
			this.isArray = true;
			Type arrayType = ((GenericArrayType) this.type).getGenericComponentType();
			ParameterizedType type = (ParameterizedType) arrayType;
			this.rawType = type.getRawType();

			if ((type.getRawType()).equals(ArrayList.class)) {
				this.componentValueType = type.getActualTypeArguments()[0];
			} else if ((type.getRawType()).equals(HashMap.class)) {
				this.componentValueType = type.getActualTypeArguments()[1];
			}
		} else if (this.type instanceof ParameterizedType) {
			ParameterizedType type = (ParameterizedType) this.type;
			this.rawType = type.getRawType();

			if ((type.getRawType()).equals(ArrayList.class)) {
				this.componentValueType = type.getActualTypeArguments()[0];
			} else if ((type.getRawType()).equals(HashMap.class)) {
				this.componentValueType = type.getActualTypeArguments()[1];
			}
		}
	}

	public String getName() {
		return this.fieldName;
	}

	public String getArrayName() {
		return this.fieldArrayName;
	}

	public boolean doTransport() {
		return dotransport;
	}

	public boolean isAttribute() {
		return isAttribute;
	}

	public boolean isArray() {
		return isArray;
	}

	public boolean isPrimitive() {
		return isPrimitive;
	}

	public Type getComponentValueType() {
		return componentValueType;
	}

	public Type getType() {
		return this.type;
	}

	public Type getRawType() {
		return rawType;
	}

	public void setValue(Object object, Object value) throws TransportException {
		try {
			this.setMethod.invoke(object, value);
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

	public Object getValue(Object object) throws TransportException {
		try {
			return this.getMethod.invoke(object);
		} catch (Exception e) {
			throw new TransportException(e);
		}
	}

}
